home *** CD-ROM | disk | FTP | other *** search
- NAME Cookie
-
- ; Cookie monster. Memory resident program that wakes up after a while
- ; and demands a cookie using a digitized voice played on the PC's speaker.
- ; User must type "cookie" to make the cookie monster happy.
-
- TEXT SEGMENT BYTE PUBLIC 'CODE'
- TEXT ENDS
-
- STK SEGMENT STACK
- DW 128 DUP (0)
- STK ENDS
-
- ASSUME CS:TEXT, DS:TEXT, ES:TEXT, SS:STK
-
- countr EQU 72 ; 16572 Hz
-
- tcadrc EQU 43h
- tcadrd EQU 40h
-
- tcmode EQU 34h
- tc2mode EQU 0B8h
-
- ppiadr EQU 61h
-
- fuselen EQU 20 ; length of fuse
-
- EXTRN Giveme:NEAR, Givemelen:WORD
- EXTRN Yum:NEAR, Yumlen:WORD
-
- TEXT SEGMENT
-
- Messptr DW 0
- Messcnt DW 0
- Fuse1 DW 0
- Fuse2 DW 0
-
- start:
- push cs ; set ds
- pop ds
-
- ; Set initial short fuse.
-
- mov Fuse1,0
- mov Fuse2,1
-
- ; Add to int 28h chain.
-
- mov ax,3528h
- int 21h
- mov WORD PTR Oldint28,bx
- mov WORD PTR Oldint28+2,es
-
- mov dx,OFFSET int28
- mov ax,2528h
- int 21h
-
- ; Terminate and stay resident.
-
- mov dx,SEG HIGHMEM
- mov ax,cs
- sub dx,ax
- mov ax,3100h
- int 21h
-
- ; int 28h interrupt routine.
-
- Oldint28 DD 0
-
- int28 PROC FAR
-
- sti ; interrupts back on
- dec cs:Fuse1 ; decrement the fuse
- jnz notyet
- dec cs:Fuse2 ; secondary fuse
- jnz notyet
-
- push ax ; save regs
- push bx
- push cx
- push dx
- push bp
- push si
- push di
- push ds
- push es
-
- mov ax,cs ; set ds and es
- mov ds,ax
- mov es,ax
-
- ; Demand a cookie and wait for the response.
-
- call getcookie
-
- ; Got it.
-
- mov ax,OFFSET Yum ; say yum
- mov Messptr,ax
- mov ax,Yumlen ; number of bytes in Yum
- mov Messcnt,ax
- call play
-
- mov Fuse2,fuselen ; reset fuse
-
- pop es ; restore regs and continue
- pop ds
- pop di
- pop si
- pop bp
- pop dx
- pop cx
- pop bx
- pop ax
- notyet:
- cli ; interrupts off
- jmp cs:Oldint28 ; continue along interrupt chain
-
- int28 ENDP
-
- ; Get a cookie from the user.
-
- getcookie PROC NEAR
-
- mov ax,OFFSET Giveme ; ask for a cookie
- mov Messptr,ax
- mov ax,Givemelen ; number of bytes in Giveme
- mov Messcnt,ax
- call play
-
- mov di,OFFSET Buf ; point to buffer
- mov si,99 ; 99 chars and room for a nul at the end
-
- ; Read characters into a buffer up to a CR.
-
- getc:
- xor ax,ax
- int 16h
- cmp al,13 ; test for CR
- je gotit
- dec si ; buffer full?
- jz gotit
- cmp al,65 ; test for uppercase
- jl lowerc
- cmp al,90
- jg lowerc
- add al,32 ; convert to lowercase
- lowerc:
- mov BYTE PTR [di],al ; store in buffer
- inc di
- jmp SHORT getc ; back for more
- gotit:
- mov BYTE PTR [di],0 ; nul terminate
-
- ; See if he typed "cookie".
-
- mov ax,OFFSET Cookie
- push ax
- mov ax,OFFSET Buf
- push ax
- call strcmp
- pop cx
- pop cx
- or ax,ax
- jne getcookie ; nope, start again
- ret
-
- getcookie ENDP
-
- Buf LABEL BYTE
- DB 100 DUP (?)
-
- Cookie LABEL BYTE
- DB "cookie", 0
-
- strcmp PROC NEAR
-
- push bp ; get frame
- mov bp,sp
-
- cld
- mov di,[bp+6] ; get str2
- mov si,di ; copy
- xor al,al
- xor cx,cx
- not cx
- repnz scasb ; find its length
- not cx
-
- mov di,si ; get str2
- mov si,[bp+4] ; get str1
- repz cmpsb ; compare strings
- mov al,[si-1] ; compare last byte
- sub al,[di-1]
- cbw
- pop bp ; restore regs and return
- ret
-
- strcmp ENDP
-
- ; Keyboard interrupt routine.
-
- Oldkbint DD 0
-
- kbint PROC FAR
-
- push ax ; save reg
-
- in al,60h ; get char from keyboard - ignore it
- in al,61h ; clear keyboard
- mov ah,al
- or al,80h
- out 61h,al
- mov al,ah
- out 61h,al
- mov al,20h ; issue EOI
- out 20h,al
-
- pop ax ; return
- iret
-
- kbint ENDP
-
- play PROC NEAR
-
- ; Substitute local keyboard interrupt routine.
-
- push es
- mov ax,3509h
- int 21h
- mov WORD PTR Oldkbint,bx
- mov WORD PTR Oldkbint+2,es
-
- mov dx,OFFSET kbint
- mov ax,2509h
- int 21h
-
- ; Get vector of current timer interrupt.
-
- mov ax,3508h
- int 21h
- mov WORD PTR Oldtmrint,bx
- mov WORD PTR Oldtmrint+2,es
-
- ; Mask timer interrupt.
-
- in al,21h
- or al,01h
- out 21h,al
-
- ; Plug in the local timer interrupt routine.
-
- mov dx,OFFSET playtimerint
- mov ax,2508h
- int 21h
-
- ; Rev up timer.
-
- mov al,tcmode
- out tcadrc,al
- mov ax,countr
- out tcadrd,al
- mov al,ah
- out tcadrd,al
-
- ; Get pointer to message.
-
- mov bx,Messptr
- mov si,Messcnt
-
- ; Initialize registers.
-
- mov bp,0 ; done flag
- mov ch,[bx] ; get first byte
- mov ah,0 ; init count
- in al,ppiadr ; get normal ppi state
- and al,0FDh ; zero speaker bit
- mov dl,al ; save for later
-
- ; Unmask timer interrupt.
-
- in al,21h
- and al,0FEh
- out 21h,al
- sti
-
- ; Test for done.
-
- ptfd: or bp,bp
- jge ptfd ; bp negative means done
-
- ; Mask timer interrupt.
-
- cli
- in al,21h
- or al,01h
- out 21h,al
- sti
-
- ; Fix timer.
-
- mov al,tcmode
- out tcadrc,al
- mov al,0
- out tcadrd,al
- out tcadrd,al
-
- ; Restore original timer interrupt vector.
-
- push ds
- lds dx,cs:Oldtmrint
- mov ax,2508h
- int 21h
- pop ds
-
- ; Unmask timer interrupt.
-
- in al,21h
- and al,0FEh
- out 21h,al
-
- ; Restore keyboard interrupt vector.
-
- push ds
- lds dx,cs:Oldkbint
- mov ax,2509h
- int 21h
- pop ds
-
- ; Figure out how long the system 18.2 Hz timer has been off.
-
- mov ax,countr
- shl ax,1
- shl ax,1
- shl ax,1
- mov cx,Messcnt
- mul cx
-
- ; Adjust the bios time of day to catch up.
-
- mov ax,40h
- mov es,ax
- mov bx,6Ch
- cli
- add es:[bx],dx
- adc WORD PTR es:[bx+2],0
- cmp WORD PTR es:[bx+2],18h
- jb biosfixed
- ja wrap
- cmp WORD PTR es:[bx],0B0h
- jb biosfixed
- wrap:
- sub WORD PTR es:[bx],0B0h
- sbb WORD PTR es:[bx+2],18h
- biosfixed:
- sti
-
- ; Exit.
-
- pop es
- ret
-
- play ENDP
-
- ; Timer interrupt routine.
-
- Oldtmrint DD 0
-
- playtimerint PROC FAR
-
- or bp,bp
- jl ptmrint1
-
- sub al,al
- rcl ch,1
- rcl al,1
- rcl al,1
- or al,dl
- out ppiadr,al
-
- inc ah
- cmp ah,8
- jne ptmrint1
- sub ah,ah
-
- inc bx
- mov ch,[bx]
- dec si
- or si,si
- jnz ptmrint1
- or bp,8000h ; done - ensure bp negative
-
- ptmrint1:
- mov al,20h
- out 20h,al
- iret
-
- playtimerint ENDP
-
- TEXT ENDS
-
- HIGHMEM SEGMENT BYTE
- HIGHMEM ENDS
-
- END start